"""
RBAC模型
包含:
1. UserRoleModel - 用户角色
2. MenuResourceModel - 菜单资源
3. ButtonResourceModel - 按钮资源
4. APIResourceModel - API资源
"""

from enum import Enum
from typing import Dict, Any

from tortoise import fields

from app.core.constants import APIResourceMethodEnum
from app.models.base_model import BaseModel


class UserRoleModel(BaseModel):
    name = fields.CharField(max_length=255, description="角色名称")
    code = fields.CharField(max_length=255, index=True, description="角色编码")
    description = fields.TextField(null=True, description="角色描述")

    menus = fields.ManyToManyField("models.MenuResourceModel", related_name="roles", through="auth_role2menu")
    apis = fields.ManyToManyField("models.APIResourceModel", related_name="roles", through="auth_role2api")
    btns = fields.ManyToManyField("models.ButtonResourceModel", related_name="roles", through="auth_role2btn")

    # Relation field
    users: fields.ManyToManyRelation["UserModel"]  # type: ignore

    class Meta:
        table = "auth_user_role"

    @property
    async def user_count(self) -> int:
        """获取角色下的用户数量"""
        return await self.users.all().count()


class MenuResourceTypeEnum(Enum):
    MENU = "MENU"
    PAGE = "PAGE"
    LINK = "LINK"


class MenuComponentLayoutEnum(Enum):
    LAYOUT_BLANK = "layout.blank"
    LAYOUT_BASE = "layout.base"


class MenuResourceModel(BaseModel):
    # 基本路由信息
    name = fields.CharField(max_length=255, description="路由键名")
    path = fields.CharField(max_length=512, description="路由路径")
    component = fields.CharField(max_length=512, description="组件路径")
    component_layout = fields.CharEnumField(
        MenuComponentLayoutEnum,
        default=MenuComponentLayoutEnum.LAYOUT_BASE,
        description="组件布局",
    )

    # Meta 信息
    title = fields.CharField(max_length=255, description="路由标题")
    i18n_key = fields.CharField(max_length=255, null=True, description="国际化键值")
    icon = fields.CharField(max_length=255, null=True, description="Iconify图标")
    local_icon = fields.CharField(max_length=255, null=True, description="本地图标")
    icon_font_size = fields.IntField(null=True, description="图标大小")
    display_order = fields.IntField(null=True, description="路由排序")
    external_link = fields.CharField(max_length=512, null=True, description="外部链接")
    hide_in_menu = fields.BooleanField(null=True, description="是否在菜单中隐藏")
    is_keep_alive = fields.BooleanField(null=True, description="是否缓存页面")
    is_constant = fields.BooleanField(null=True, description="是否为固定路由")
    active_menu = fields.CharField(max_length=255, null=True, description="激活的菜单项")
    multi_tab = fields.BooleanField(null=True, description="是否支持多标签")
    fixed_index_in_tab = fields.IntField(null=True, description="固定标签页顺序")
    query_params = fields.JSONField(null=True, description="路由查询参数")

    # 关系字段
    parent = fields.ForeignKeyField(
        "models.MenuResourceModel", related_name="children", null=True, description="父级路由"
    )
    roles: fields.ManyToManyRelation["UserRoleModel"]
    buttons: fields.ReverseRelation["ButtonResourceModel"]
    apis: fields.ManyToManyRelation["APIResourceModel"]

    class Meta:
        table = "auth_menu_resource"

    async def to_dict(self) -> Dict[str, Any]:
        """
        转换为前端路由格式，完全匹配 Vue Router 的 RouteMeta 类型定义

        Returns:
            Dict[str, Any]: 符合前端路由规范的字典格式
        """

        # 处理查询参数格式
        formatted_query = None
        if self.query_params:
            formatted_query = [{"key": k, "value": str(v)} for k, v in self.query_params.items()]

        # 构建 meta 对象
        meta = {
            "title": self.title,
            "i18nKey": self.i18n_key,
            "keepAlive": self.is_keep_alive,
            "constant": self.is_constant,
            "icon": self.icon,
            "localIcon": self.local_icon,
            "iconFontSize": self.icon_font_size,
            "order": self.display_order,
            "href": self.external_link,
            "hideInMenu": self.hide_in_menu,
            "activeMenu": self.active_menu,
            "multiTab": self.multi_tab,
            "fixedIndexInTab": self.fixed_index_in_tab,
            "query": formatted_query,
        }

        # 移除 None 值
        meta = {k: v for k, v in meta.items() if v is not None}

        # 构建基础路由对象
        route = {
            "name": self.name,
            "path": self.path,
            "component": f"{self.component_layout.value}${self.component}",
            "meta": meta,
            "id": self.id,
            "parentId": self.parent_id,
        }
        return route

    @property
    async def child_count(self) -> int:
        """获取子菜单数量"""
        return await self.children.all().count()


class ButtonResourceModel(BaseModel):
    name = fields.CharField(max_length=255, description="名称")
    code = fields.CharField(max_length=255, description="编码")
    description = fields.TextField(null=True, description="描述")
    menu = fields.ForeignKeyField("models.MenuResourceModel", related_name="btns", null=True)

    # 反向关系
    roles: fields.ManyToManyRelation["UserRoleModel"]
    apis: fields.ManyToManyRelation["APIResourceModel"]

    class Meta:
        table = "auth_button_resource"


class APIResourceModel(BaseModel):
    name = fields.CharField(max_length=255, description="名称")
    description = fields.TextField(null=True, description="描述")
    action_desc = fields.CharField(max_length=255, null=True, description="动作描述，操作日志基于此")

    api_identifier = fields.CharField(max_length=512, index=True, description="url")
    method = fields.CharEnumField(
        APIResourceMethodEnum,
        default=APIResourceMethodEnum.GET,
        description="method",
    )
    is_dynamic = fields.BooleanField(default=False, description="是否是动态路由")
    is_whitelist = fields.BooleanField(default=False, description="是否是白名单")
    button = fields.ManyToManyField(
        "models.ButtonResourceModel", related_name="apis", null=True, through="auth_api2button"
    )
    menu = fields.ManyToManyField("models.MenuResourceModel", related_name="apis", null=True, through="auth_api2menu")
    # 反向关系
    roles: fields.ManyToManyRelation["UserRoleModel"]

    class Meta:
        table = "auth_api_resource"

    @property
    def full_api_identifier(self) -> str:
        """获取完整的API标识符"""
        return f"{self.method.value}:{self.api_identifier}"
